package com.company.gjtx.common.service.impl;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.company.gjtx.common.dao.GenericDao;
import com.company.gjtx.common.exception.BusinessException;
import com.company.gjtx.common.exception.DaoException;
import com.company.gjtx.common.service.GenericManager;
import com.company.gjtx.common.util.DateProcessorUtil;
import com.company.gjtx.common.util.PageView;

public class GenericManagerImpl<T, ID extends Serializable> implements
		GenericManager<T, ID> {

	protected static final Log logger = LogFactory
			.getLog(GenericManagerImpl.class);

	protected GenericDao<T, ID> genericDao;

	protected Class<T> type;

	public GenericManagerImpl() {
	}

	public GenericManagerImpl(Class<T> type) {
		this.type = type;
	}

	/***************************************************************************
	 * 检测传入的对象是否满足保存或更新的要求
	 * 
	 * @return boolean
	 * @throws BusinessException
	 */
	public boolean check(T entity) throws BusinessException {
		return true;
	}

	/***************************************************************************
	 * 保存实体，
	 * 
	 * @return ID
	 * @throws BusinessException
	 */
	public ID save(T entity) throws BusinessException {
		try {
			if (check(entity)) {
				try {
					return getGenericDao().save(entity);
				} catch (DaoException e) {
					e.printStackTrace();
					throw new BusinessException(e.getMessage());
				}
			} else {
				throw new BusinessException("待保存的对象 [" + entity.toString()
						+ "] 不符合保存条件，无法保存！");
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 保存或者更新实体对象
	 * 
	 * @return void
	 * @throws BusinessException
	 * @throws BusinessException
	 */
	public void saveOrUpdate(T entity) throws BusinessException {
		try {
			if (check(entity)) {
				try {
					getGenericDao().saveOrUpdate(entity);
				} catch (DaoException e) {
					e.printStackTrace();
					throw new BusinessException(e.getMessage());
				}
			} else {
				throw new BusinessException("待保存的对象 [" + entity.toString()
						+ "] 不符合保存条件，无法保存！");
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 更新或者保存集合
	 * 
	 * @return void
	 * @throws BusinessException
	 */
	public void saveOrUpdateAll(Collection<T> entities)
			throws BusinessException {
		try {
			for (T entity : entities) {
				boolean checkResult = check(entity);
				if (!checkResult) {
					throw new BusinessException("待保存集合中的对象 ["
							+ entity.toString() + "] 不符合保存条件，无法保存！");
				}
			}
			try {
				getGenericDao().saveOrUpdateAll(entities);
			} catch (DaoException e) {
				e.printStackTrace();
				throw new BusinessException(e.getMessage());
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 根据ID查询
	 * 
	 * @param id
	 * @return T
	 */
	public T findById(ID id) throws BusinessException {
		try {
			return getGenericDao().findById(id);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 查询所有
	 * 
	 * @param
	 * @return List<T>
	 * @throws BusinessException
	 */
	public List<T> findAll() throws BusinessException {
		try {
			return getGenericDao().findAll();
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 根据某一属性查询
	 * 
	 * @param id
	 * @return T
	 * @throws BusinessException
	 */
	public List findByProperty(String propertyName, Object value)
			throws BusinessException {
		try {
			String className = type.getName();
			StringBuffer hql = new StringBuffer();
			hql.append(" from ").append(className).append(" where ");
			if (value instanceof String) {
				hql.append(propertyName + " = '" + value).append("'  ");
			} else if (value instanceof Date) {
				hql.append(
						propertyName + " = '"
								+ DateProcessorUtil.formatDateObject(value))
						.append("'  ");
			} else {
				hql.append(propertyName + " = " + value);
			}
			getGenericDao().setHql(hql.toString());
			try {
				return getGenericDao().findAllByHql();
			} catch (DaoException e) {
				e.printStackTrace();
				throw new BusinessException(e.getMessage());
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 分页查询
	 * 
	 * @param page,size
	 * @return List<T>
	 * @throws BusinessException
	 */
	public PageView<T> findByPage(PageView<T> pageView)
			throws BusinessException {
		try {
			return getGenericDao().findByPage(pageView);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 根据条件查询数据 Set的量不要太大
	 * 
	 * @param page,size
	 * @return List<T>
	 * @throws BusinessException
	 */
	public List<T> findByCondition(Map<String, Object> conditions)
			throws BusinessException {
		try {
			String className = type.getName();
			StringBuffer hql = new StringBuffer();
			hql.append(" from " + className);
			if (conditions != null && conditions.size() != 0) {
				hql.append(" where ");
				for (String key : conditions.keySet()) {
					Object value = conditions.get(key);
					if (value instanceof String) {
						if (value != null
								&& !((String) value).trim().equals("")) {
							hql.append(key + " like '%" + value + "%' and ");
						}
					} else if (value instanceof Date) {
						hql.append(key + " = '"
								+ DateProcessorUtil.formatDateObject(value)
								+ "' and ");
					} else if (value instanceof Collection) {
						Iterator<Long> itValue = ((Collection) value)
								.iterator();
						hql.append(key + " in (");
						while (itValue.hasNext()) {
							Long tmpLong = itValue.next();
							hql.append(tmpLong + ",");
						}
						hql.delete(hql.lastIndexOf(","), hql.length());
						hql.append(") and ");
					}

					else {
						hql.append(key + " = " + value + " and ");
					}
				}
				hql.delete(hql.lastIndexOf("and"), hql.length());
			}
			getGenericDao().setHql(hql.toString());
			try {
				return getGenericDao().findAllByHql();
			} catch (DaoException e) {
				e.printStackTrace();
				throw new BusinessException(e.getMessage());
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 分页查询
	 * 
	 * @param page,size
	 * @return List<T>
	 * @throws BusinessException
	 */
	public PageView<T> findByPage(Map<String, Object> conditions,
			PageView<T> pageView) throws BusinessException {
		try {
			String className = type.getName();

			StringBuffer hql = new StringBuffer();
			hql.append(" from " + className);

			if (conditions != null && conditions.size() != 0) {
				hql.append(" where ");
				for (String key : conditions.keySet()) {
					Object value = conditions.get(key);
					if (value instanceof String) {
						if (value != null
								&& !((String) value).trim().equals("")) {
							hql.append(key + " like '%" + value + "%' and ");
						}
					} else if (value instanceof Date) {
						hql.append(key + " = '"
								+ DateProcessorUtil.formatDateObject(value)
								+ "' and ");
					} else {
						hql.append(key + " = " + value + " and ");
					}
				}
				hql.delete(hql.lastIndexOf("and"), hql.length());
			}
			getGenericDao().setHql(hql.toString());
			System.out.println(getGenericDao().getHql().toString());
			try {
				return getGenericDao().findByPage(pageView);
			} catch (DaoException e) {
				e.printStackTrace();
				throw new BusinessException(e.getMessage());
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/*
	 * (non-Javadoc)通过特定表的链接来查询
	 * 
	 * @see cn.com.ctsi.room.manager.common.GenericManager#findByPage(java.util.Map,
	 *      cn.com.ctsi.room.util.PageView, java.util.Map, java.util.Map)
	 */
	public PageView<T> findByPage(Map<String, Object> conditions,
			PageView<T> pageView,
			LinkedHashMap<Class, String> tableAndJoinConditions,
			Map<Class, Map<String, Object>> exConditions)
			throws BusinessException {
		try {
			String className = type.getName();
			String simpleClassName = type.getSimpleName().toLowerCase();

			StringBuffer hql = new StringBuffer();
			StringBuffer joinConditions = new StringBuffer();
			hql.append(" from " + className + " " + simpleClassName);
			hql.append(joinConditions.toString());
			Iterator<Entry<Class, String>> it = tableAndJoinConditions
					.entrySet().iterator();
			while (it.hasNext()) {
				Entry<Class, String> tmp = it.next();
				hql.append(", ").append(tmp.getKey().getName()).append(" ")
						.append(tmp.getKey().getSimpleName().toLowerCase());
				joinConditions.append(" and ").append(tmp.getValue());
			}
			if (conditions != null && conditions.size() != 0) {
				hql.append(" where ");
				for (String key : conditions.keySet()) {
					Object value = conditions.get(key);
					if (value instanceof String) {
						if (value != null
								&& !((String) value).trim().equals("")) {
							hql.append(simpleClassName + "." + key + " like '%"
									+ value + "%' and ");
						}
					} else if (value instanceof Date) {
						hql.append(simpleClassName + "." + key + " = '"
								+ DateProcessorUtil.formatDateObject(value)
								+ "' and ");
					} else if (value instanceof Collection) {
						Iterator<Long> itValue = ((Collection) value)
								.iterator();
						hql.append(simpleClassName + "." + key + " in (");
						while (itValue.hasNext()) {
							Long tmp = itValue.next();
							hql.append(tmp + ",");
						}
						hql.delete(hql.lastIndexOf(","), hql.length());
						hql.append(") and ");
					} else {
						hql.append(simpleClassName + "." + key + " = " + value
								+ " and ");
					}
				}
				hql.delete(hql.lastIndexOf("and"), hql.length());
			}

			if (exConditions != null && exConditions.size() != 0) {
				Iterator<Entry<Class, Map<String, Object>>> itExConditions = exConditions
						.entrySet().iterator();
				while (itExConditions.hasNext()) {
					if (hql.indexOf("where") == -1) {
						hql.append(" where ");
					} else {
						hql.append(" and ");
					}
					Entry<Class, Map<String, Object>> tmp = itExConditions
							.next();
					String exClassName = tmp.getKey().getSimpleName()
							.toLowerCase();
					if (tmp.getValue() != null && tmp.getValue().size() != 0) {
						Iterator<Entry<String, Object>> tmpExCondition = tmp
								.getValue().entrySet().iterator();
						while (tmpExCondition.hasNext()) {
							Entry<String, Object> tmpConditon = tmpExCondition
									.next();
							if (tmpConditon.getValue() instanceof String) {
								if (tmpConditon.getValue() != null
										&& !((String) tmpConditon.getValue())
												.trim().equals("")) {
									hql.append(exClassName + "."
											+ tmpConditon.getKey() + " like '%"
											+ tmpConditon.getValue()
											+ "%' and ");
								}
							} else if (tmpConditon.getValue() instanceof Date) {
								hql
										.append(exClassName
												+ "."
												+ tmpConditon.getKey()
												+ " = '"
												+ DateProcessorUtil
														.formatDateObject(tmpConditon
																.getValue())
												+ "' and ");
							} else if (tmpConditon.getValue() instanceof Collection) {
								Iterator<Long> itValue = ((Collection) tmpConditon
										.getValue()).iterator();
								hql.append(exClassName + "."
										+ tmpConditon.getKey() + " in (");
								while (itValue.hasNext()) {
									Long tmpLong = itValue.next();
									hql.append(tmpLong + ",");
								}
								hql.delete(hql.lastIndexOf(","), hql.length());
								hql.append(") and ");

							} else {
								hql.append(exClassName + "."
										+ tmpConditon.getKey() + " = "
										+ tmpConditon.getValue() + " and ");
							}
						}
						hql.delete(hql.lastIndexOf("and"), hql.length());
					}
				}
			}
			hql.append(joinConditions.toString());
			getGenericDao().setHql(hql.toString());
			System.out.println(getGenericDao().getHql().toString());
			try {
				return getGenericDao().findByPageEx(pageView);
			} catch (DaoException e) {
				e.printStackTrace();
				throw new BusinessException(e.getMessage());
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 分页查询
	 * 
	 * @param page,size
	 * @return List<T>
	 * @throws BusinessException
	 */
	public int getPageSize(int size) throws BusinessException {
		try {
			return getGenericDao().getPageSize(size);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 获取总行数
	 * 
	 * @return int
	 * @throws BusinessException
	 */
	public int getTotalRows() throws BusinessException {
		try {
			return getGenericDao().getTotalRows();
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 修改实体T
	 * 
	 * @return void
	 */
	public void modify(T entity) throws BusinessException {
		try {
			if (check(entity)) {
				try {
					getGenericDao().modify(entity);
				} catch (DaoException e) {
					e.printStackTrace();
					throw new BusinessException(e.getMessage());
				}
			} else {
				throw new BusinessException("要更新的实体对象[" + entity.toString()
						+ "] 不符合更新条件，无法更新!");
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 检测传入的实体是否允许删除
	 * 
	 * @param entity :
	 *            待检测的实体
	 * @return 是否允许删除。true为允许删除；false为不允许删除
	 * @throws BusinessException
	 */
	public boolean removeCheck(T entity) throws BusinessException {
		return true;
	}

	/**
	 * 删除实体
	 * 
	 * @return void
	 * @throws BusinessException
	 */
	public void remove(T entity) throws BusinessException {
		try {
			if (removeCheck(entity)) {
				try {
					getGenericDao().remove(entity);
				} catch (DaoException e) {
					e.printStackTrace();
					throw new BusinessException(e.getMessage());
				}
			} else {
				throw new BusinessException("待删除的对象 [" + entity.toString()
						+ "] 不符合删除条件，无法删除！");
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 删除实体，脱离事务控制
	 * 
	 * @return void
	 * @throws BusinessException
	 */
	public void specialRemove(T entity) throws BusinessException {
		try {
			if (removeCheck(entity)) {
				try {
					getGenericDao().remove(entity);
				} catch (DaoException e) {
					e.printStackTrace();
					throw new BusinessException(e.getMessage());
				}
			} else {
				throw new BusinessException("待删除的对象 [" + entity.toString()
						+ "] 不符合删除条件，无法删除！");
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	/**
	 * 删除集合中的所有数据
	 * 
	 * @return void
	 * @throws BusinessException
	 */
	public void removeAll(Collection<T> entities) throws BusinessException {
		try {
			for (T entity : entities) {
				boolean checkResult = removeCheck(entity);
				if (!checkResult) {
					throw new BusinessException("待删除集合中的对象 ["
							+ entity.toString() + "] 不符合删除条件，无法删除！");
				}
			}
			try {
				getGenericDao().removeAll(entities);
			} catch (DaoException e) {
				e.printStackTrace();
				throw new BusinessException(e.getMessage());
			}
		} catch (BusinessException be) {
			be.printStackTrace();
			throw be;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	public void updateAllByHql(Set<Long> idSet, T entity, String pkStr)
			throws BusinessException {
		if (idSet == null || idSet.size() == 0) {
			throw new BusinessException("请勾选后删除！");
		}
		StringBuffer hql = new StringBuffer();
		List<Field> allField = new ArrayList<Field>();
		hql.append(" update " + entity.getClass().getSimpleName() + " set ");
		Field[] fieldsuper = entity.getClass().getSuperclass()
				.getDeclaredFields(); // 获取实体类的所有属性，返回Field数组
		Field[] fieldChild = entity.getClass().getDeclaredFields();
		if (fieldsuper != null)
			allField.addAll(Arrays.asList(fieldsuper));
		if (fieldChild != null)
			allField.addAll(Arrays.asList(fieldChild));
		Iterator<Field> itField = allField.iterator();
		while (itField.hasNext()) { // 遍历所有属性
			Field field = itField.next();
			try {
				field.setAccessible(true);
				Object obj = field.get(entity);
				if (obj != null && !field.getName().equals("serialVersionUID")
						&& !field.getName().equals(pkStr)) {
					if (obj instanceof String && !obj.equals("")) {
						hql.append(" " + field.getName() + "='" + obj + "',");
					} else if (obj instanceof Date) {
						hql.append(" " + field.getName() + "='"
								+ DateProcessorUtil.formatDateObject(obj)
								+ "',");
					} else {
						hql.append(" " + field.getName() + "=" + obj + ",");
					}
				}
			} catch (IllegalArgumentException e) {
			} catch (IllegalAccessException e) {
			}
		}
		hql.delete(hql.lastIndexOf(","), hql.length());
		hql.append(" where " + pkStr + " in (");
		Iterator<Long> it = idSet.iterator();
		while (it.hasNext()) {
			hql.append(it.next() + ",");
		}
		hql.delete(hql.lastIndexOf(","), hql.length());
		hql.append(")");
		try {
			getGenericDao().setHql(hql.toString());
			getGenericDao().updateAllByHql();
		} catch (DaoException e) {
			e.printStackTrace();
			throw new BusinessException(e.getMessage());
		}
	}

	public GenericDao<T, ID> getGenericDao() {
		return genericDao;
	}

	public void setGenericDao(GenericDao<T, ID> genericDao) {
		this.genericDao = genericDao;
	}

}